package com.datang.litejvm.cmd;

import com.datang.litejvm.constant.ConstantInfo;
import com.datang.litejvm.constant.ConstantPool;
import com.datang.litejvm.engin.ExecutionResult;
import com.datang.litejvm.engin.StackFrame;

import java.util.HashMap;
import java.util.Map;

/**
 * @author: 顶风少年
 * @Description: 字节码指令父类
 * @date: 22:05 2022/6/15
 **/
public abstract class ByteCodeCommand {
    //指令code
    String opCode;
    //偏移量
    private int offset;
    //常量池
    public ConstantPool pool;

    public static final String new_object = "bb";
    public static final String invokespecial = "b7";
    public static final String invokevirtual = "b6";
    public static final String getfield = "b4";
    public static final String putfield = "b5";
    public static final String getstatic = "b2";
    public static final String ldc = "12";
    public static final String dup = "59";
    public static final String bipush = "10";
    public static final String aload_0 = "2a";
    public static final String aload_1 = "2b";
    public static final String aload_2 = "2c";
    public static final String aload_3 = "2d";
    public static final String iload_0 = "1a";
    public static final String iload_1 = "1b";
    public static final String iload_2 = "1c";
    public static final String iload_3 = "1d";
    public static final String fload_3 = "25";
    public static final String voidreturn = "b1";
    public static final String astore_0 = "4b";
    public static final String astore_1 = "4c";
    public static final String astore_2 = "4d";
    public static final String astore_3 = "4e";
    public static final String iadd = "60";
    public static final String istore_0 = "3b";
    public static final String istore_1 = "3c";
    public static final String istore_2 = "3d";
    public static final String istore_3 = "3e";
    public static final String iconst_0 = "03";
    public static final String iconst_1 = "04";
    public static final String iconst_2 = "05";
    public static final String iconst_3 = "06";
    public static final String if_icmpne = "a0";
    public static final String if_icmpge = "a2";
    public static final String if_icmpgt = "a3";
    public static final String if_icmple = "a4";
    public static final String goto_no_condition = "a7";
    public static final String iinc = "84";

    private static Map<String, String> codeMap = new HashMap<String, String>();
    static {
        codeMap.put("bb", "new");
        codeMap.put("b7", "invokespecial");
        codeMap.put("b6", "invokevirtual");
        codeMap.put("b4", "getfield");
        codeMap.put("b5", "putfield");
        codeMap.put("b2", "getstatic");
        codeMap.put("12", "ldc");
        codeMap.put("59", "dup");
        codeMap.put("10", "bipush");
        codeMap.put("2a", "aload_0");
        codeMap.put("2b", "aload_1");
        codeMap.put("2c", "aload_2");
        codeMap.put("2d", "aload_3");
        codeMap.put("1a", "iload_0");
        codeMap.put("1b", "iload_1");
        codeMap.put("1c", "iload_2");
        codeMap.put("1d", "iload_3");
        codeMap.put("25", "fload_3");
        codeMap.put("b1", "return");
        codeMap.put("4b", "astore_0");
        codeMap.put("4c", "astore_1");
        codeMap.put("4d", "astore_2");
        codeMap.put("4e", "astore_3");
        codeMap.put("60", "iadd");
        codeMap.put("3b", "istore_0");
        codeMap.put("3c", "istore_1");
        codeMap.put("3d", "istore_2");
        codeMap.put("3e", "istore_3");
        codeMap.put("03", "iconst_0");
        codeMap.put("04", "iconst_1");
        codeMap.put("05", "iconst_2");
        codeMap.put("06", "iconst_3");
        codeMap.put("a0", "if_icmpne");
        codeMap.put("a2", "if_icmpge");
        codeMap.put("a3", "if_icmpgt");
        codeMap.put("a4", "if_icmple");
        codeMap.put("a7", "goto_no_condition");
        codeMap.put("84", "iinc");
    }

    protected ByteCodeCommand(ConstantPool pool, String opCode) {
        this.opCode = opCode;
        this.pool = pool;
    }

    public int getOffset() {
        return offset;
    }

    public void setOffset(int offset) {
        this.offset = offset;
    }

    public String getOpCode() {
        return opCode;
    }

    public void setOpCode(String opCode) {
        this.opCode = opCode;
    }

    /**
     * @author: 顶风少年
     * @Description: 获取当前指令的含义
     * @date: 17:24 2022/6/16
     **/
    public String getReadableCodeText() {
        String txt = codeMap.get(opCode);
        if (txt == null) {
            return opCode;
        }
        return txt;
    }

    /**
     * @author: 顶风少年
     * @Description: 从常量池中获取常量项
     * @date: 18:24 2022/6/16
     **/
    protected ConstantInfo getConstantInfo(int index) {
        return this.pool.getConstantInfo(index);
    }

    public abstract int getLength();

    public  String toString(){
        return getOffset() + ":" + getOpCode() + " " + getReadableCodeText();
    }

    public abstract void execute(StackFrame frame, ExecutionResult result);
}
